Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize paste from clipboard #17

Merged
merged 1 commit into from
Jan 3, 2023

Conversation

Ircama
Copy link
Contributor

@Ircama Ircama commented Dec 11, 2022

Allow pasting Python expressions from the clipboard

@timrid
Copy link
Owner

timrid commented Dec 11, 2022

What is the use case for this? Can you make an example?

Probably I will not merge it, because using eval on untrusted strings is a security issue. See https://stackoverflow.com/a/10964364

@Ircama
Copy link
Contributor Author

Ircama commented Dec 12, 2022

What is the use case for this? Can you make an example?

An example would be this: b'\x00\x00\x00\xa4\xc18\xe1\x81_\x00\xcc#b\x0c\r\x15'

Probably I will not merge it, because using eval on untrusted strings is a security issue. See https://stackoverflow.com/a/10964364

Yes, I know. I was considering construct-editor mainly an engineering tool (BTW, an excellent sw indeed, thanks!) for developers and testers. In such use case maybe eval would still be adeguate....

@Ircama Ircama force-pushed the ircama-python-from-clipboard branch from daca13f to 88f3cec Compare December 12, 2022 21:28
@Ircama
Copy link
Contributor Author

Ircama commented Dec 12, 2022

[EDITED] Updated code with improved robustness on the Python expression evaluation from clipboard, using the safe_tokens configuration variable, which defines a restricted list of safe tokens to be used. The code also allows usage of numbers, strings (but not f-strings) and operands, so that standard math, byte and string expressions can be used. Optionally, safe_tokens can be overridden for specific purposes.

The code cannot protect from any attach, like inputting an expression that evaluates to a huge number: 10**10**100

Perhaps for dev/testing use, this could be anyway acceptable.

@Ircama Ircama force-pushed the ircama-python-from-clipboard branch from 88f3cec to 1aea013 Compare December 12, 2022 23:29
@Ircama
Copy link
Contributor Author

Ircama commented Dec 13, 2022

An alternative method would be to add a menu toggle to the hex editor, allowing pasting Python expressions. I'll try working on such a mode as soon as I have time.

@Ircama Ircama force-pushed the ircama-python-from-clipboard branch from 1aea013 to 66be153 Compare December 27, 2022 00:44
@Ircama
Copy link
Contributor Author

Ircama commented Dec 27, 2022

This is an almost complete rewrite of the previous code which enhances the default mode of the paste from clipboard interpreter of the hex editor (now hex strings copied from a wide variety of tracers can be directly pasted to the hex editor) and also adds a menu toggle, allowing pasting Python expressions from the clipboard, with robust evaluation: other than using the safe_tokens configuration variable, which defines a restricted list of safe tokens to be interpreted, the code catches most (if not all) the existing "eval" exploits (f-strings, long-running math computations, tokens).

Examples of strings allowed with the default paste mode:

0102030405060708090a0b0c0d0e0f
01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
01.02.03.04.05.06.07.08.09.0a.0b.0c.0d.0e.0f
01-02-03-04-05-06-07-08-09-0a-0b-0c-0d-0e-0f
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f
1 2 3 4 5 6 7 8 9 a b c d e f
"71 20 98 00 c0 7a 3e 6a 8d 7c c4 0d 04 10 02 f2 00"
("71 20 98 00 c0 7a 3e 6a 8d 7c c4 0d 04 10 02 f2 00")
bytes.fromhex("71 20 98 00 c0 7a 3e 6a 8d 7c c4 0d 04 10 02 f2 00")
'71209800c07a3e6a8d7cc40d041002f200'

Examples of strings allowed with the Python paste mode:

bytes.fromhex("71 20 98 00 c0 7a 3e 6a 8d 7c c4 0d 04 10 02 f2 00")
b'\x00\x00\x00\xa4\xc18\xe1\x81_\x00\xcc#b\x0c\r\x15'
bytes.fromhex("0102030405060708090a0b0c0d0e0f" + "000101")

Examples of appropriately discarded Python strings when using the Python paste mode:

2 ** 2 ** 2 ** 2
"()"*8**5
'(1,' * 100 + ')' * 100
10**10**100
"foo" + f"{().__class__.__base__}"
"foo" + "bar"
bytes.fromhex("0102030405060708090a0b0c0d0e0f" + f"{().__class__.__base__}")
1 + "two"
2/0
1,2,3
import time

@timrid
Copy link
Owner

timrid commented Dec 27, 2022

Thanks for your work on my project.

I still don't like the approach with eval though. That's too much magic happening in the background that a user would never expect when inserting. Even though you put some effort into it, I'm not going to merge it that way.
If you use the widgets in another project, you can create copy and paste hooks/callbacks, which you can use in your project to implement this feature more easily.

But I like the improvements of the string parsing. Maybe the following format would be practical, which I often have in C/C++ code: 0x12, 0x23, 0x45,

@Ircama
Copy link
Contributor Author

Ircama commented Dec 27, 2022

Maybe the following format would be practical, which I often have in C/C++ code: 0x12, 0x23, 0x45,

I do not want to further insist on the usage of eval, just inform that, pasting 0x12, 0x23, 0x45, with the "Allow pasting Python expression" checked, these bytes are correctly added.

@Ircama
Copy link
Contributor Author

Ircama commented Dec 29, 2022

you can create copy and paste hooks/callbacks, which you can use in your project to implement this feature more easily.

developing a plugin looks fine

Maybe the following format would be practical, which I often have in C/C++ code: 0x12, 0x23, 0x45,

OK, I'll try to work out a possible solution without using eval and supporting constructs like 0x12, 0x23, 0x45

@Ircama Ircama force-pushed the ircama-python-from-clipboard branch from 66be153 to d31a418 Compare December 29, 2022 19:42
@Ircama Ircama changed the title Python expressions from the clipboard Optimize paste from clipboard Dec 29, 2022
@Ircama
Copy link
Contributor Author

Ircama commented Dec 29, 2022

Code revised to support the following formats (with no usage of eval):

0102030405060708090a0b0c0d0e0f
01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
01.02.03.04.05.06.07.08.09.0a.0b.0c.0d.0e.0f
01-02-03-04-05-06-07-08-09-0a-0b-0c-0d-0e-0f
1,2,3,4,5,6,7,8,9,a,b,c,d,e,f
1 2 3 4 5 6 7 8 9 a b c d e f
"71 20 98 00 c0 7a 3e 6a 8d 7c c4 0d 04 10 02 f2 00"
("71 20 98 00 c0 7a 3e 6a 8d 7c c4 0d 04 10 02 f2 00")
bytes.fromhex("71 20 98 00 c0 7a 3e 6a 8d 7c c4 0d 04 10 02 f2 00")
'71209800c07a3e6a8d7cc40d041002f200'
0x12, 0x23, 0x45,
b'\x00\x00\x00\xa4\xc18\xe1\x81_\x00\xcc#b\x0c\r\x15'

Optionally, a plugin might be implemented by overriding methods in the HexEditorGrid class (e.g., methods build_context_menu() and string_to_byts() allow this easily and can be reused) and then monkey patching the HexEditorGrid reference used by the library, like in the following "myplugin" example:

from construct_editor.wx_widgets.wx_hex_editor import (
    HexEditorGrid, ContextMenuItem)

class HexEditorGrid(HexEditorGrid):
    ...
    def build_context_menu(self):
        menus = super().build_context_menu()
        ...  # process the "menus" list
        return menus

    def string_to_byts(self, byts_str: str):
        ...
        return super().string_to_byts(byts_str)

Monkey patch:

import construct_editor as cseditor
from myplugin import HexEditorGrid
...
cseditor.wx_widgets.wx_hex_editor.HexEditorGrid = HexEditorGrid
...
editor_panel = cseditor.wx_widgets.WxConstructHexEditor(...)

Example of build_context_menu override:

    def build_context_menu(self):
        menus = super().build_context_menu()
        menus.Append(None)  # separator
        menus.Append(
            ContextMenuItem(
                wx_id=wx.ID_ANY,
                name="my new context menu toggle",
                callback=lambda event: self.my_specific_function(),
                toggle_state=my_state,  # None = option, True = toggle selected, False = toggle unselected
                enabled=not self.read_only,
            )
        )
        return menus

Example of string_to_byts override:

    def string_to_byts(self, byts_str: str):
        if my_condition:
            return my_string_processor(byts_str)
        else:
            return super().string_to_byts(byts_str)

@Ircama Ircama force-pushed the ircama-python-from-clipboard branch from d31a418 to 2ba7b59 Compare December 30, 2022 01:49
timrid added a commit that referenced this pull request Jan 2, 2023
@timrid
Copy link
Owner

timrid commented Jan 3, 2023

Thanks for your contribution. I will merge this PR. But I am also working on an different branch where I refactored many files in this repository. But I applied your changes to the other branch manually, with a few modifications. The next release will be based on the refactored branch.

@timrid timrid merged commit 8e38716 into timrid:main Jan 3, 2023
@timrid timrid mentioned this pull request Jan 3, 2023
@Ircama Ircama deleted the ircama-python-from-clipboard branch January 8, 2023 15:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants